package com.linkage.bss.crm.multidb.util;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class RouteUtil
{
  private static final Logger log = LoggerFactory.getLogger(RouteUtil.class);
  
  public static Integer CONST_STATE_USABLE = new Integer(1);
  
  public static final String CONST_DEFAULT_DATA_SOURCE = "dataSource";
  public static final String CONST_INDEX_DATA_SOURCE = "indexDataSource";
  public static final String CONST_SKIP_ROUTE = "SKIP_ROUTE";
  public static final String[] CONST_REQ_NAME_4_AREA_ID = { "bssInnerAreaId" };
  public static final String[] CONST_REQ_AREA_JSON = { "areaJson" };
  public static final String[] CONST_REQ_NAME_4_AREA_CODE = { "bssInnerAreaCode" };
  
  public static final String CONST_BUSI_CODE_BIZHALL = "bizHall";
  
  public static final String CONST_NAME_DBROUTER_SMO = "dbRouterManager.routerAssistSMO";
  public static final int ACTION_CLASS_CUST_ACTION = 1;
  public static final int ACTION_CLASS_ACCT_ACTION = 2;
  public static final int ACTION_CLASS_OFFER_ACTION = 3;
  public static final int ACTION_CLASS_PROD_ACTION = 4;
  public static final int ACTION_CLASS_ORDER_ACTION = 5;
  private static ThreadLocal<String> preAreaId = new ThreadLocal();
  
  private static ThreadLocal<String> preAreaCode = new ThreadLocal();
  
  private static ThreadLocal<String> routeAreaInfo = new ThreadLocal();
  
  private static ThreadLocal<String> curRequestAreaId = new ThreadLocal();
  
  private static ThreadLocal<String> curSessionAreaId = new ThreadLocal();
  
  private static ThreadLocal<String> curAreaCode = new ThreadLocal();
  
  public static final boolean isLogInvokeInfo = false;
  public static final Map<String, Integer> AREACODE_AREAID_MAP = new HashMap();
  public static final Map<String, String> ROUTE_2_DATASOURCE_MAP = new HashMap();
  
  static { AREACODE_AREAID_MAP.put("025", new Integer(3));
    AREACODE_AREAID_MAP.put("0511", new Integer(4));
    AREACODE_AREAID_MAP.put("0510", new Integer(15));
    AREACODE_AREAID_MAP.put("0512", new Integer(20));
    AREACODE_AREAID_MAP.put("0513", new Integer(26));
    AREACODE_AREAID_MAP.put("0514", new Integer(33));
    AREACODE_AREAID_MAP.put("0515", new Integer(39));
    AREACODE_AREAID_MAP.put("0516", new Integer(48));
    AREACODE_AREAID_MAP.put("0517", new Integer(60));
    AREACODE_AREAID_MAP.put("0518", new Integer(63));
    AREACODE_AREAID_MAP.put("0519", new Integer(69));
    AREACODE_AREAID_MAP.put("0523", new Integer(79));
    AREACODE_AREAID_MAP.put("0527", new Integer(84));
    
    RouteUtil routeUtil = new RouteUtil();
    Properties config = routeUtil.getConfigInfo("constConfig.properties");
    ROUTE_2_DATASOURCE_MAP.put("0000", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0000"));
    ROUTE_2_DATASOURCE_MAP.put("025", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_025"));
    ROUTE_2_DATASOURCE_MAP.put("0510", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0510"));
    ROUTE_2_DATASOURCE_MAP.put("0511", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0511"));
    ROUTE_2_DATASOURCE_MAP.put("0512", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0512"));
    ROUTE_2_DATASOURCE_MAP.put("0513", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0513"));
    ROUTE_2_DATASOURCE_MAP.put("0514", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0514"));
    ROUTE_2_DATASOURCE_MAP.put("0515", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0515"));
    ROUTE_2_DATASOURCE_MAP.put("0516", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0516"));
    ROUTE_2_DATASOURCE_MAP.put("0517", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0517"));
    ROUTE_2_DATASOURCE_MAP.put("0518", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0518"));
    ROUTE_2_DATASOURCE_MAP.put("0519", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0519"));
    ROUTE_2_DATASOURCE_MAP.put("0523", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0523"));
    ROUTE_2_DATASOURCE_MAP.put("0527", config.getProperty("CONST_ROUTE_2_DATASOURCE_MAP_KEY_0527"));
  }
  
  private Properties getConfigInfo(String configFileName) {
    Properties pro = null;
    InputStream stream = null;
    try {
      stream = getClass().getClassLoader().getResourceAsStream(configFileName);
      pro = new Properties();
      pro.load(stream);
    } catch (Exception e) {
      log.error("读取配置文件{}异常:", new Object[] { configFileName, e });
      try {
        if (stream != null) {
          stream.close();
        }
      } catch (IOException ioe) {
        log.error("关闭流IO异常:", ioe);
      }
      
      if (stream != null) {
//        try {
//          stream.close();
//        } catch (IOException e) {
//          log.error("关闭流IO异常:", e);
//        }
      }
    }
    finally
    {
      if (stream != null)
        try {
          stream.close();
        } catch (IOException e) {
          log.error("关闭流IO异常:", e);
        }
    }
    return pro;
  }
  
  public static String getPreAreaId() {
    return (String)preAreaId.get();
  }
  
  public static void setPreAreaId(String areaId) {
    preAreaId.set(areaId);
  }
  
  public static String getPreAreaCode() {
    return (String)preAreaCode.get();
  }
  
  public static void setPreAreaCode(String areaCode) {
    preAreaCode.set(areaCode);
  }
  
  public static String getRouteAreaInfo() {
    return (String)routeAreaInfo.get();
  }
  
  public static void setRouteAreaInfo(String areaInfo) {
    routeAreaInfo.set(areaInfo);
  }
  
  public static void initPreAreaInfo() {
    preAreaId.set(null);
    preAreaCode.set(null);
  }
  
  public static void setPreAreaInfo() {
    
    if (getCurAreaCode() != null) {
      setPreAreaCode(getCurAreaCode());
    } else if (getCurRequestAreaId() != null) {
      setPreAreaId(getCurRequestAreaId());
    } else if (getCurSessionAreaId() != null) {
      setPreAreaId(getCurSessionAreaId());
    }
  }
  
  public static void rollbackAreaInfo() {
    
    if (getPreAreaCode() != null) {
      setCurAreaCode(getPreAreaCode());
    } else if (getPreAreaId() != null) {
      setCurRequestAreaId(getPreAreaId());
    }
  }
  
  private static void switchRouteAreaIdCommon(JSONObject routeJson) {
    if (!isJsonNodeEmpty(routeJson, "askAreaId")) {
      setCurRequestAreaId(routeJson.getString("askAreaId"));
    } else if (!isJsonNodeEmpty(routeJson, "partyAreaId")) {
      setCurRequestAreaId(routeJson.getString("partyAreaId"));
    }
  }
  
  public static void switchRouteAreaId() {
    String routeInfo = getRouteAreaInfo();
    if ((routeInfo == null) || ("".equals(routeInfo)) || ("null".equals(routeInfo))) {
      return;
    }
    JSONObject routeJson = JSONObject.fromObject(routeInfo);
    switchRouteAreaIdCommon(routeJson);
  }
  
  public static void switchRouteAreaId(int actionClassCd, Long id) {
    String routeInfo = getRouteAreaInfo();
    if ((routeInfo == null) || ("".equals(routeInfo)) || ("null".equals(routeInfo))) {
      return;
    }
    boolean switchSucess = false;
    JSONObject routeJson = JSONObject.fromObject(routeInfo);
    if (id == null) {
      switchRouteAreaIdCommon(routeJson);
      return;
    }
    if (routeJson.containsKey("specialObjAreaId")) {
      JSONObject specJson = routeJson.getJSONObject("specialObjAreaId");
      if (1 == actionClassCd) {
        if (specJson.containsKey("partyObjAreaIds")) {
          JSONArray partyArr = specJson.getJSONArray("partyObjAreaIds");
          for (int i = 0; i < partyArr.size(); i++) {
            JSONObject partyJson = partyArr.getJSONObject(i);
            if (id.equals(Long.valueOf(partyJson.getLong("partyId")))) {
              setCurRequestAreaId(partyJson.getString("areaId"));
              switchSucess = true;
              break;
            }
          }
        }
      } else if (2 == actionClassCd) {
        if (specJson.containsKey("accountObjAreaIds")) {
          JSONArray partyArr = specJson.getJSONArray("accountObjAreaIds");
          for (int i = 0; i < partyArr.size(); i++) {
            JSONObject partyJson = partyArr.getJSONObject(i);
            if (id.equals(Long.valueOf(partyJson.getLong("accountId")))) {
              setCurRequestAreaId(partyJson.getString("areaId"));
              switchSucess = true;
              break;
            }
          }
        }
      } else if (3 == actionClassCd) {
        if (specJson.containsKey("offerObjAreaIds")) {
          JSONArray partyArr = specJson.getJSONArray("offerObjAreaIds");
          for (int i = 0; i < partyArr.size(); i++) {
            JSONObject partyJson = partyArr.getJSONObject(i);
            if (id.equals(Long.valueOf(partyJson.getLong("offerId")))) {
              setCurRequestAreaId(partyJson.getString("areaId"));
              switchSucess = true;
              break;
            }
          }
        }
      } else if ((4 == actionClassCd) && 
        (specJson.containsKey("prodObjAreaIds"))) {
        JSONArray partyArr = specJson.getJSONArray("prodObjAreaIds");
        for (int i = 0; i < partyArr.size(); i++) {
          JSONObject partyJson = partyArr.getJSONObject(i);
          if (id.equals(Long.valueOf(partyJson.getLong("prodId")))) {
            setCurRequestAreaId(partyJson.getString("areaId"));
            switchSucess = true;
            break;
          }
        }
      }
    }
    
    if (!switchSucess) {
      switchRouteAreaIdCommon(routeJson);
    }
  }
  
  public static String getRoute2Datasource(String areaCode) {
    return (String)ROUTE_2_DATASOURCE_MAP.get(areaCode);
  }
  
  public static String getCurAreaCode() {
    return (String)curAreaCode.get();
  }
  
  public static void setCurAreaCode(String areaCode) {
    initAreaInfo();
    curAreaCode.set(areaCode);
  }
  
  public static void setCurRequestAreaId(String requestAreaId) {
    initAreaInfo();
    curRequestAreaId.set(requestAreaId);
    log.debug("请求中包含的地区：{}", new Object[] { requestAreaId });
  }
  
  public static String getCurRequestAreaId() {
    return (String)curRequestAreaId.get();
  }
  
  public static String getCurSessionAreaId() {
    return (String)curSessionAreaId.get();
  }
  
  public static void setCurSessionAreaId(String sessionAreaId) {
    initAreaInfo();
    curSessionAreaId.set(sessionAreaId);
  }
  
  public static void initAreaInfo()
  {
    curSessionAreaId.set(null);
    curRequestAreaId.set(null);
    curAreaCode.set(null);
  }
  
  public static Integer getAvailableAreaId()
  {
    if (getCurAreaCode() != null) {
      return (Integer)AREACODE_AREAID_MAP.get(getCurAreaCode());
    }
    if (getCurRequestAreaId() != null)
      return Integer.valueOf(getCurRequestAreaId());
    if (getCurSessionAreaId() != null) {
      return Integer.valueOf(getCurSessionAreaId());
    }
    log.error("按优先级获得可用的areaID为空", new Object[0]);
    throw new RuntimeException("按优先级获得可用的areaID为空!!!");
  }
  
  private static boolean isJsonNodeEmpty(JSONObject json, String key)
  {
    if (json.containsKey(key)) {
      Object obj = json.get(key);
      if ((obj == null) || (obj.equals(null)) || (obj.equals("")) || (obj.equals("null"))) {
        return true;
      }
      return false;
    }
    
    return true;
  }
}
